xander

Overview
State management library; works like redux but with option for many stores, side effects, Promises and other practical things.
Library includes:
- createStore(name, reducerOrSpec, actionsOrSelectors)
- dispatch(action)
- getStores()
- getReducer()
- getState()
- promiseAction(type, data)
- replaceState(state)
- subscribe(cb)
Quick start
npm install --save xander
import rootStore, {
createStore,
dispatch,
getStores,
getState,
promiseAction,
replaceState,
subscribe
}
from 'xander'
let storeA = createStore('a', (state=0, action) =>
action.type === 'setA' ?
action.data : state )
let storeB = createStore('b', (state=0, action) =>
action.type === 'setB' ?
action.data : state )
let storeC = createStore('c', (state=0, action, waitFor) => {
waitFor([storeA.dispatchToken, storeB.dispatchToken]);
return storeA.getState() + storeB.getState();
})
rootStore.subscribe((...args) => console.log('action', ...args))
rootStore.dispatch('setA', 2)
rootStore.dispatch('setB', 2)
rootStore.getState()
Polyfills
This library depends on a modern JavaScript runtime. Load a polyfill like in core-js or babel-polyfill to support old browsers.
Manually install required polyfills with core-js:
require('core-js/fn/promise');
require('core-js/fn/object/assign');
require('core-js/fn/object/freeze');
require('core-js/fn/object/keys');
API
createStore( name, reducerOrSpec, actionsOrSelectors )
A store responds to actions by returning the next state.
const inc = 'inc'
import {createStore} from 'xander';
var store = createStore( "CountStoreWithReducer", (state=0, action) => {
switch (action.type)
case inc:
return state + 1;
case incN:
return state + action.data;
default:
return state;
}, {
inc: (state) => dispatch('inc'),
incN: (state, count) => dispatch('incN', count),
})
store.dispatch('inc')
store.inc()
Optionally, you may define a store with a specification.
const inc = 'inc'
import { createStore } from 'xander';
var countStore = createStore( "CountStoreWithSpec", {
getInitialState: () => 0,
inc: (state) => state+1,
incN: (state, n) => state+n,
})
countStore.inc()
countStore.incN(10)
dispatch( action )
The entry point to effecting state changes in the app is when an action is dispatch.
Dispatch accepts action as object, promise, or type/data; returns promise.
var { dispatch } = require( 'xander' )
dispatch( { type: 'openPath', '/user/new' } )
.then( action => console.log('Going', action.data) )
dispatch( Promise.resolve({ type: 'get', mode: 'off the juice' }) )
dispatch( 'loadSettings', { a: 1, b: 2 } )
Store Properties
Here is a list of store properties that are part of the public API.
name | comment |
---|
name | The name of the store |
dispatch | Access to dispatch function |
dispatchToken | A number used to identity the store |
subscribe | A function to tegister a listener |
getState | A function to access state |
setState | Replace the store's state |
replaceReducer | Replace the store's reducer |
getStores( )
Returns an object with the name as key and store as value.
replaceState( state )
Rehydrate the root state.
replaceState({
'MyCountStore': 1
})
subscribe( listener )
Listen to changes to all stores. This will trigger once each time createStore or dispatch is invoked.
Please note that action will be undefined when createStore is invoked.
var unsubscribe = subscribe( (state, action) => {
// got change
})
// stop listening
unsubscribe()
getReducer( )
Return app's reducer function, use with Redux.